package assignment1.eventplan.request;

import android.support.annotation.StringDef;
import android.support.v4.util.Pools;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * <pre>
 * {
 * "destination_addresses" : [ "Vancouver, BC, Canada" ],
 * "origin_addresses" : [ "75 Bell St, Chagrin Falls, OH 44022, USA" ],
 * "rows" : [
 *          {
 *          "elements" : [
 *              {
 *              "distanceText" : {
 *                  "text" : "4,293 km",
 *                  "value" : 4292616
 *                  },
 *              "duration" : {
 *                  "text" : "9 days 10 hours",
 *                  "value" : 814219
 *                  },
 *              "status" : "OK"
 *              }
 *          ]
 *          }
 *      ],
 *  "status" : "OK"
 *  }
 * </pre>
 */
public class MatrixResult {

    public String error;
    private String distanceText;
    private String durationText;
    private int durationValue;
    private int distanceValue;

    @StringDef({Status.OK, Status.INVALID_REQUEST, Status.MAX_ELEMENTS_EXCEEDED, Status.OVER_QUERY_LIMIT, Status.REQUEST_DENIED, Status.UNKNOWN_ERROR})
    @Retention(RetentionPolicy.SOURCE)
    public @interface Status {
        String OK = "OK";
        String INVALID_REQUEST = "INVALID_REQUEST";
        String MAX_ELEMENTS_EXCEEDED = "MAX_ELEMENTS_EXCEEDED";
        String OVER_QUERY_LIMIT = "OVER_QUERY_LIMIT";
        String REQUEST_DENIED = "REQUEST_DENIED";
        String UNKNOWN_ERROR = "UNKNOWN_ERROR";
    }

    @StringDef({ElementStatus.OK, ElementStatus.NOT_FOUND, ElementStatus.ZERO_RESULTS})
    @Retention(RetentionPolicy.SOURCE)
    public @interface ElementStatus {
        String OK = "OK";
        String NOT_FOUND = "NOT_FOUND";
        String ZERO_RESULTS = "ZERO_RESULTS";
    }

    private static final Pools.SynchronizedPool<MatrixResult> sPool
            = new Pools.SynchronizedPool<>(
            10);


    public static MatrixResult obtain(Response response) {
        MatrixResult result = sPool.acquire();
        if (null == result) {
            result = new MatrixResult();
        } else {
            result.reset();
        }
        try {
            JSONObject jsonObject = new JSONObject(response.getData());
            String status = jsonObject.optString("status");
            if (Status.OK.equals(status)) {
                JSONArray rows = jsonObject.optJSONArray("rows");
                if (null != rows) {
                    int size = rows.length();
                    for (int i = 0; i < size; i++) {
                        JSONObject obj = rows.optJSONObject(i);
                        JSONArray array = obj.optJSONArray("elements");
                        if (null != array) {
                            int elementsSize = array.length();
                            for (int j = 0; j < elementsSize; j++) {
                                JSONObject element = array.optJSONObject(i);

                                String elementStatus = element.optString("status");
                                if (!ElementStatus.OK.equals(elementStatus)) {
                                    result.error = elementStatus;
                                    continue;
                                }

                                JSONObject distance = element.optJSONObject("distance");
                                JSONObject duration = element.optJSONObject("duration");
                                result.distanceText = distance.optString("text");
                                result.distanceValue = distance.optInt("value");
                                result.durationText = duration.optString("text");
                                result.durationValue = duration.optInt("value");
                                return result;
                            }
                        }
                    }
                }
            } else {
                result.error = status;
            }
        } catch (JSONException e) {
            e.printStackTrace();
            result.error = e.getMessage();
        }
        return result;

    }

    private void reset() {
        error = null;
        distanceText = null;
        durationText = null;
        distanceValue = 0;
        durationValue = 0;
    }

    public String getDistanceText() {
        return distanceText;
    }

    public String getDurationText() {
        return durationText;
    }

    public int getDurationValue() {
        return durationValue;
    }

    public int getDistanceValue() {
        return distanceValue;
    }

    public static void recycle(MatrixResult result) {
        sPool.release(result);
    }
}
